package org.openscheduler.modules.trigger;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.openscheduler.modules.scheduler.SchedulerService;
import org.openscheduler.modules.trigger.support.ComputeFireTimeUtils;
import org.openscheduler.modules.trigger.support.ScheduleBuilderMaker;
import org.quartz.CalendarIntervalScheduleBuilder;
import org.quartz.CronScheduleBuilder;
import org.quartz.DailyTimeIntervalScheduleBuilder;
import org.quartz.ScheduleBuilder;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TriggerService {
	
	@Autowired
	SchedulerService schedulerService;
	
	public Trigger getTrigger(String schedName, TriggerKey triggerKey) throws SchedulerException {
		Scheduler scheduler = schedulerService.getScheduler(schedName);
		return scheduler.getTrigger(triggerKey);
	}
	
	public Trigger getTrigger(String schedName, String triggerKeyName, String triggerKeyGroup) throws SchedulerException {
		return getTrigger(schedName, TriggerKey.triggerKey(triggerKeyName, triggerKeyGroup));
	}
	
	public List<Trigger> getAllTriggers(String schedName) throws SchedulerException {
		List<Trigger> triggers = new ArrayList<Trigger>();
		Scheduler scheduler = schedulerService.getScheduler(schedName);
		for (String triggerGroupName : scheduler.getTriggerGroupNames()) {
			for (TriggerKey triggerKey : scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(triggerGroupName))) {
				Trigger trigger = scheduler.getTrigger(triggerKey);
				triggers.add(trigger);
			}
		}
		return triggers;
	}
	
	public boolean checkExists(String schedName, TriggerKey triggerKey) throws SchedulerException {
		Scheduler scheduler = schedulerService.getScheduler(schedName);
		return scheduler.checkExists(triggerKey);
	}

	public boolean checkExists(String schedName, String triggerKeyName, String triggerKeyGroup) throws SchedulerException {
		return checkExists(schedName, TriggerKey.triggerKey(triggerKeyName, triggerKeyGroup));
	}
	
	public List<Date> computeFireTimes(Trigger trigger, int numTimes) {
		return ComputeFireTimeUtils.computeFireTimes(trigger, numTimes);
	}
	
	public List<Date> computeFireTimes(String cronExpression, int numTimes) {
		return ComputeFireTimeUtils.computeFireTimes(cronExpression, numTimes);
	}
	
	public void calendarIntervalScheduleJob(String schedName, CalendarIntervalScheduleTriggerTemplate template) throws SchedulerException {
		CalendarIntervalScheduleBuilder builder = ScheduleBuilderMaker.builder(template);
		scheduleJob(schedName, template, builder);
	}
	
	public void cronScheduleJob(String schedName, CronScheduleTriggerTemplate template) throws SchedulerException {
		CronScheduleBuilder builder = ScheduleBuilderMaker.builder(template);
		scheduleJob(schedName, template, builder);
	}
	
	public void dailyTimeIntervalScheduleJob(String schedName, DailyTimeIntervalScheduleTriggerTemplate template) throws SchedulerException {
		DailyTimeIntervalScheduleBuilder builder = ScheduleBuilderMaker.builder(template);
		scheduleJob(schedName, template, builder);
	}
	
	public void simpleScheduleJob(String schedName, SimpleScheduleTriggerTemplate template) throws SchedulerException {
		SimpleScheduleBuilder builder = ScheduleBuilderMaker.builder(template);
		scheduleJob(schedName, template, builder);
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Date scheduleJob(String schedName, TriggerTemplate triggerTemplate, ScheduleBuilder scheduleBuilder) throws SchedulerException {
		TriggerBuilder<? extends Trigger> triggerBuilder = TriggerBuilder.newTrigger();
		
		triggerBuilder.withIdentity(triggerTemplate.getTriggerKey());
		triggerBuilder.forJob(triggerTemplate.getKeyOfJobToFire());
		triggerBuilder.withSchedule(scheduleBuilder);
		
		if (triggerTemplate.getTriggerEndTime() != null) {
			triggerBuilder.endAt(triggerTemplate.getTriggerEndTime());	
		}
		
		if (triggerTemplate.getCalName() != null) {
			triggerBuilder.modifiedByCalendar(triggerTemplate.getCalName());	
		}

		if (triggerTemplate.getNewJobDataMap() != null) {
			triggerBuilder.usingJobData(triggerTemplate.getNewJobDataMap());	
		}
		
		if (triggerTemplate.getTriggerDescription() != null) {
			triggerBuilder.withDescription(triggerTemplate.getTriggerDescription());	
		}
		
		if (triggerTemplate.getTriggerPriority() != null) {
			triggerBuilder.withPriority(triggerTemplate.getTriggerPriority());	
		}
		
		// TODO : 아래 두개 분기처리 해야함. 둘다 startTime 프로퍼티 제어
//		if (beTrigger.getTriggerStartTime() != null) {
//			triggerBuilder.startAt(beTrigger.getTriggerStartTime());	
//		} 
//		
//		if (beTrigger.isStartNow()) {
//			triggerBuilder.startNow();
//		}
		
		if (triggerTemplate.getTriggerStartTime() != null) {
			triggerBuilder.startAt(triggerTemplate.getTriggerStartTime());	
		} else {
			triggerBuilder.startNow();
		}
		 
		Trigger trigger = triggerBuilder.build();
		Scheduler scheduler = schedulerService.getScheduler(schedName);
		return scheduler.scheduleJob(trigger);
	}
	
}
